from loa_game import WHITE, BLACK, LinesOfActionState, SpinAction, MoveAction, DIRECTIONS, Direction
from game_agent import GameAgent
from alpha_beta import AlphaBetaSearch
from heu import alot, num_con, variance, glob_sum_dis, square

# A bloody large number.
INFINITY = 1.0e400

class agent(GameAgent):
    
    def move(self, game_state):
        play = self.search(game_state)
        try:
            self.played.append(
                     game_state._getMoveAction( play.row, play.col, play.direction))
        except:
            self.played.append(
                     game_state._getSpinAction( play.row, play.col))
        return play
    
    def setup(self, player, game_state, turn_time_limit, setup_time_limit):
        self.player = player
        self.played = []
        u = lambda state: self.utility(state)
        #self.alphaBeta = AlphaBetaSearch(self.player, 3, u)
        self.max_depth = 3

    def utility(self, state):
        winner = state.getWinner()
        if winner is None:
            return alot(state)
        elif winner == self.player:
            return 1
        else:
            return -1
    
    def search(self, current_state):
        
        best_value = -INFINITY
        
        states = current_state.getSuccessors().items()
        #for action, state in states:
            
        for action, state in states:
            #lets get rid of the worst node?
            value_fn = self._getValueFn(state)
            value = value_fn(state, best_value, INFINITY, 1)
            if value > best_value:
                best_value = value
                best_action = action
        
        return best_action
    
    def _getValueFn(self, state):
        if state.getCurrentPlayer() == self.player:
            return self._maxValue
        else:
            return self._minValue
    
    def _cutoffTest(self, state, depth):
        
        return depth >= self.max_depth or (state.getWinner() is not None)
    
    def _maxValue(self, state, alpha, beta, depth):
        
        #player turn
        
        if self._cutoffTest(state, depth):
            return self.utility(state)
        
        successors = state.getSuccessors()
        
        value = INFINITY
        v = -INFINITY
        for key,successor in successors.items():
            val = square(successor)
            if value >= val:
                value = val
                k = key
            if v <= val:
                v = val
                k_ = key
            #deadlock breaking, not necessarily good, but less boring
            if successors in self.played:
                #bad programming remove an item while iterating on a list
                del(successors[key])
        del(successors[k])
        successors = successors.values()
        
        
        value = -INFINITY
        
        for successor in successors:
            value_fn = self._getValueFn(successor)
            value = max(value, value_fn(successor, alpha, beta, depth + 1))
            if value >= beta:
                return value
            alpha = max(alpha, value)
        
        return value
    
    def _minValue(self, state, alpha, beta, depth):
        
        #other turn
        
        if self._cutoffTest(state, depth):
            return self.utility(state)
        
        successors = state.getSuccessors()
        
        value = INFINITY
        v = -INFINITY
        for key,successor in successors.items():
            val = square(successor)
            if value >= val:
                value = val
                k = key
            if v <= val:
                v = val
                k_ = key
        del(successors[k_])
        successors = successors.values()
        
        value = INFINITY
        for successor in successors:
            value_fn = self._getValueFn(successor)
            value = min(value, value_fn(successor, alpha, beta, depth + 1))
            if value <= alpha:
                return value
            beta = min(beta, value)
        
        return value


